import {
  checkRouteViewDepath,
  getDataSet,
  getOffsetParent,
  setDataSet,
  hasOwn,
} from "./tools";

/**
 * 焦点、区域构造类
 */
export default class Creater {
  constructor(elem, binding, vnode) {
    elem.__$Focus__ = this;
    let name = binding.name;
    let data = binding.value;
    // 构建焦点
    let {
      assign,
      appoints,
      group,
      id,
      popup,
      routeDepath,
      routerEl,
      routeVpath,
      sign,
    } = this.createDataSet(elem, binding, vnode.context);
    let { vBlur, vFocus } = this.getEvent(vnode);
    this.assign = assign;
    this.appoints = appoints;
    this.data = data;
    this.elem = elem;
    this.group = group;
    this.id = id;
    this.name = name;
    this.popup = popup;
    this.routeDepath = routeDepath;
    this.routerEl = routerEl;
    this.routeVpath = routeVpath;
    this.selected = assign;
    this.sign = sign;
    this.vBlur = vBlur;
    this.vFocus = vFocus;
  }

  // 元素X方向位置
  get left() {
    return getOffsetParent(this.elem, "left");
  }

  // 元素Y方向位置
  get top() {
    return getOffsetParent(this.elem, "top");
  }

  // 元素宽度
  get width() {
    return this.elem.offsetWidth;
  }

  // 元素高度
  get height() {
    return this.elem.offsetHeight;
  }

  /**
   * 获取元素dataset内容
   * @param {HTMLElement|Element} elem html元素节点
   * @param {Object} binding 自定义指令绑定的对象
   * @param {Object} context 虚拟节点中的context
   * @returns Object
   */
  createDataSet(elem, binding, context) {
    let id =
      binding.name +
      "-" +
      (Math.random() + Date.now()).toString(36).replace(/\./, "");
    let { routeDepath, routeVpath, routerEl } = checkRouteViewDepath(context);
    setDataSet(elem, { id, routeDepath, routeVpath });
    let dataSet = getDataSet(elem);
    let assign = hasOwn(dataSet, "assign");
    let appoints = hasOwn(dataSet, "appoints");
    return { ...dataSet, assign, appoints, routerEl };
  }

  /**
   * 获取节点绑定的事件
   * @param {Vnode} vnode 虚拟节点
   * @returns Object
   */
  getEvent(vnode) {
    let listeners = {};
    if (vnode.componentOptions) {
      listeners = vnode.componentOptions.listeners || {};
    } else {
      listeners = vnode.data.on || {};
    }
    return listeners;
  }

  /**
   * 更新焦点
   * @param {HTMLElement|Element} elem 元素节点
   * @param {Object} binding 自定义指令绑定的对象
   * @param {Vnode} vnode 虚拟节点
   */
  update(elem, binding, vnode) {
    let data = binding.value;
    let dataSet = getDataSet(elem);
    let { group, popup, sign } = dataSet;
    let assign = hasOwn(dataSet, "assign");
    let appoints = hasOwn(dataSet, "appoints");
    let { vFocus, vBlur } = this.getEvent(vnode);
    Object.assign(this, {
      assign,
      appoints,
      data,
      group,
      popup,
      sign,
      vFocus,
      vBlur,
    });
  }
}
